#include <stdlib.h>
#include <string.h>
#include "FileHeader.h"
#include "../utils/Utils.h"

using namespace zipUtils;

FileHeader::FileHeader() : fileHeader_(0x04034b50)
{
}

FileHeader::FileHeader(char* fileName) : fileHeader_(0x04034b50)
{
    fileNameLength_ = strlen(fileName);
    fileName_ = (char*) malloc((fileNameLength_ * sizeof (char)) + 1);
    memset(fileName_, 0, fileNameLength_);
    strcpy(fileName_, fileName);
    fileName_[fileNameLength_] = 0;
}

FileHeader::FileHeader(const FileHeader& other) : fileHeader_(0x04034b50)
{
    initialize(other.fileName_, other.absolutePath_, other.buffer_, other.bufferSize_, other.extraField_,
            other.extraFieldLength_, other.fileData_, other.fileDataLength_);
    
    compressedSize_ = other.compressedSize_;
    compressionMethod_ = other.compressionMethod_;
    crc_ = other.crc_;
    flag_ = other.flag_;
    lastModificationDate_ = other.lastModificationDate_;
    lastModificationTime_ = other.lastModificationTime_;
    unCompressedSize_ = other.unCompressedSize_;
    versionToExtract_ = versionToExtract_;


}

FileHeader& FileHeader::operator =(const FileHeader& other)
{
    initialize(other.fileName_, other.absolutePath_, other.buffer_, other.bufferSize_, other.extraField_,
            other.extraFieldLength_, other.fileData_, other.fileDataLength_);
    compressedSize_ = other.compressedSize_;
    compressionMethod_ = other.compressionMethod_;
    crc_ = other.crc_;
    flag_ = other.flag_;
    lastModificationDate_ = other.lastModificationDate_;
    lastModificationTime_ = other.lastModificationTime_;
    unCompressedSize_ = other.unCompressedSize_;
    versionToExtract_ = versionToExtract_;
    return *this;
}

FileHeader::~FileHeader()
{
    if (!fileName_)
        free(fileName_);
    if (!absolutePath_)
        free(absolutePath_);
    if (!buffer_)
        free(buffer_);
    if (!extraField_)
        free(extraField_);
    if (!fileData_)
        free(fileData_);
}

bool FileHeader::operator ==(const FileHeader& other)
{
    return strcmp(other.absolutePath_, absolutePath_) == 0;
}

void FileHeader::initialize(const char* fileName, const char* absolutePath, const char* buffer,
        size_t bufferLength, const char* extraField, size_t extraFieldLength, const char* fileData,
        size_t fileDataLength)
{
    fileNameLength_ = strlen(fileName);
    fileName_ = (char*) malloc(fileNameLength_ * sizeof (char));
    memset(fileName_, 0, fileNameLength_);
    strcpy(fileName_, fileName);

    absolutePath_ = (char*) malloc(strlen(absolutePath) * sizeof (char));
    memset(absolutePath_, 0, strlen(absolutePath));
    strcpy(absolutePath_, absolutePath);
    
    bufferSize_ = bufferLength;
    buffer_ = (char*) malloc(bufferSize_);
    memset(buffer_, 0, bufferSize_);
    conCat(buffer_, buffer, 0, bufferLength);
    
    extraFieldLength_ = extraFieldLength;
    extraField_ = (char*) malloc(extraFieldLength_);
    memset(extraField_, 0, extraFieldLength_);
    conCat(extraField_, extraField, 0, extraFieldLength);
    
    fileDataLength_ = fileDataLength;
    fileData_ = (char*) malloc(fileDataLength_);
    memset(fileData_, 0, fileDataLength_);
    conCat(fileData_, fileData, 0, fileDataLength);
}

void FileHeader::setAbsolutePath(const char* absolutePath)
{
    if (!absolutePath_)
    {
        free(absolutePath_);
        absolutePath_ = 0;
    }
    absolutePath_ = (char*) malloc(strlen(absolutePath) * sizeof (char));
    strcpy(absolutePath_, absolutePath);
}

void FileHeader::setCompressedSize(const int compressedSize)
{
    compressedSize_ = compressedSize;
}

void FileHeader::setCompressionMethod(const short compressionMethod)
{
    compressionMethod_ = compressionMethod;
}

void FileHeader::setCrc(const int crc)
{
    crc_ = crc;
}

void FileHeader::setExtraField(const char* extraField)
{
    if (!extraField_)
    {
        free(extraField_);
        extraField_ = 0;
    }
    extraFieldLength_ = strlen(extraField);
    extraField_ = (char*) malloc(extraFieldLength_ * sizeof (char));
    memset(extraField_, 0, extraFieldLength_);
    strcpy(extraField_, extraField);
}

void FileHeader::setExtraFieldLength(const short extraFieldLength)
{
    extraFieldLength_ = extraFieldLength;
}

void FileHeader::setFileData(const char* fileData, const size_t fileDataLength)
{
    if (!fileData_)
    {
        free(fileData_);
        fileData_ = 0;
    }
    fileData_ = (char*) malloc(fileDataLength);
    memset(fileData_, 0, fileDataLength);
    fileDataLength_ = fileDataLength;
    conCat(fileData_, fileData, 0, fileDataLength);
}

void FileHeader::setFileName(char* fileName)
{
    if (!fileName)
    {
        free(fileName);
        fileName = 0;
    }
    fileNameLength_ = strlen(fileName);
    fileName_ = (char*) malloc(fileNameLength_ * sizeof (char));
    memset(fileName_, 0, fileNameLength_);
    strcpy(fileName_, fileName);
}

void FileHeader::setFlag(const short flag)
{
    flag_ = flag;
}

void FileHeader::setLastModificationDate(const short lastModificationDate)
{
    lastModificationDate_ = lastModificationDate;
}

void FileHeader::setLastModificationTime(const short lastModificationTime)
{
    lastModificationTime_ = lastModificationTime;
}

void FileHeader::setUnCompressedSize(const int unCompressedSize)
{
    unCompressedSize_ = unCompressedSize;
}

void FileHeader::setVersionToExtract(const short versionToExtract)
{
    versionToExtract_ = versionToExtract;
}

size_t FileHeader::getBufferSize()
{
    return bufferSize_;
}

size_t FileHeader::getFileDataLength()
{
    return fileDataLength_;
}

char* FileHeader::getAbsolutePath()
{
    return absolutePath_;
}

char* FileHeader::getBuffer()
{
    return buffer_;
}

char* FileHeader::getExtraField()
{
    return extraField_;
}

char* FileHeader::getFileData()
{
    return fileData_;
}

char* FileHeader::getFileName()
{
    return fileName_;
}

short FileHeader::getCompressionMethod()
{
    return compressionMethod_;
}

short FileHeader::getExtraFieldLentgth()
{
    return extraFieldLength_;
}

short FileHeader::getFileNameLength()
{
    return fileNameLength_;
}

short FileHeader::getFlag()
{
    return flag_;
}

short FileHeader::getLastModificationDate()
{
    return lastModificationDate_;
}

short FileHeader::getLastModificationTime()
{
    return lastModificationTime_;
}

short FileHeader::getVersionToExtract()
{
    return versionToExtract_;
}

int FileHeader::getCompressedSize()
{
    return compressedSize_;
}

int FileHeader::getCrc()
{
    return crc_;
}

int FileHeader::getUncompressedSize()
{
    return unCompressedSize_;
}

char* FileHeader::buildFileHeader()
{
    bufferSize_ = 30 + fileNameLength_ + extraFieldLength_ + fileDataLength_;
    buffer_ = (char*) malloc(bufferSize_);
    memset(buffer_, 0, bufferSize_);
    copy(buffer_, &fileHeader_, 0, sizeof (int));
    copy(buffer_, &versionToExtract_, 4, sizeof (short));
    copy(buffer_, &flag_, 6, sizeof (short));
    copy(buffer_, &compressionMethod_, 8, sizeof (short));
    copy(buffer_, &lastModificationTime_, 10, sizeof (short));
    copy(buffer_, &lastModificationDate_, 12, sizeof (short));
    copy(buffer_, &crc_, 14, sizeof (int));
    copy(buffer_, &compressedSize_, 18, sizeof (int));
    copy(buffer_, &unCompressedSize_, 22, sizeof (int));
    copy(buffer_, &fileNameLength_, 26, sizeof (short));
    copy(buffer_, &extraFieldLength_, 28, sizeof (short));
    conCat(buffer_, fileName_, 30, fileNameLength_);
    conCat(buffer_, fileData_, 30 + fileNameLength_, fileDataLength_);
    return buffer_;
}
